/******************************************************************************
 * Copyright 2022 The AIR Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#pragma once
#include <cstddef>

namespace base {
namespace basic {

template <bool U, size_t N>
struct Align {
  static constexpr size_t value =
      Align<U, (N >> 1) + (U && N & 1 ? 1 : 0)>::value << 1;
};

template <bool U>
struct Align<U, 1> {
  static constexpr size_t value = 1;
};

template <bool U>
struct Align<U, 0> {
  static constexpr size_t value = 0;
};

template <size_t N>
using AlignUp = Align<true, N>;

template <size_t N>
using AlignDown = Align<false, N>;

inline size_t AlignNumber(bool up, size_t num) {
  size_t exp = 0;
  while (num > 1) {
    ++exp;
    if (up && num & 1) {
      num = (num >> 1) + 1;
    } else {
      num >>= 1;
    }
  }
  return num << exp;
}

}  // namespace basic
}  // namespace base
